﻿using Framework.Models;
using Framework.Models.Entities;
using Framework.Models.Request;
using Framework.Repository;
using Framework.Utility.Helper;
using Framework.Utility.ViewModels;

namespace Framework.Code.FlowWork;

public class FlowCenter
{
    private readonly FlowHandle _flowHandle;
    private readonly IFlowinstanceRepository _flowinstanceRepository;
    private readonly IFlowschemeRepository _flowschemeRepository;


    private static UserCacheModel user = new UserCacheModel()
    {
        UserId = "1",//1301
        UserName = "admin"  //张三
    };
    public FlowCenter(IFlowinstanceRepository flowinstanceRepository,
        IFlowschemeRepository flowschemeRepository,
        FlowHandle flowHandle)
    {
        _flowinstanceRepository = flowinstanceRepository;
        _flowschemeRepository = flowschemeRepository;
        _flowHandle = flowHandle;
    }

    /// <summary>
    /// 注册流程实例
    /// </summary>
    /// <param name="model"></param>
    /// <param name="obj"></param>
    /// <returns></returns>
    public TData onRegisterFlowinstance(RegisterFlow model, object obj)
    {
        var flowScheme = _flowschemeRepository.GetFirstOrDefault(c => !string.IsNullOrEmpty(c.Id));//.GetByKey(model.flowSchemeId);
                                                                                                   //获取条件节点 的 判断条件
        model.frmData = _flowHandle.GetFrmData(obj, flowScheme.FrmContentData);

        var instance = new Fw_Flowinstance
        {
            Id = model.flowInstanceId,
            FlowCode = model.flowInstanceId,
            CustomName = model.flowInstanceName,
            FlowLevel = model.FlowLevel,
            ApplyUserId = model.applyUserId,
            ApplyUserName = model.applyUserName,
            SchemeId = flowScheme.Id,
            ConfluenceNo = 0,
            ConfluenceOk = 0,
            FrmData = model.frmData,
            SchemeContent = flowScheme.SchemeContent,
            FrmContentData = flowScheme.FrmContentData,
        };

        FlowRuntime flowRuntime = new FlowRuntime(instance);
        instance.PreviousId = flowRuntime.currentNodeId;
        instance.ActivityId = flowRuntime.nextNodeId;
        instance.ActivityName = flowRuntime.nextNode?.nodeName ?? Define.FlowEndTitle;
        instance.ActivityType = flowRuntime.nextNode?.nodeType ?? (int)FlowNodeType.End;
        instance.MakerList = _flowHandle.GetFlowNextMakers(flowRuntime);
        instance.CreateTime = DateTime.Now;
        instance.CreateBy = model.applyUserName;

        var count = _flowinstanceRepository.Insert(instance);
        return count > 0 ? new TData(ResultTag.success) : new TData(ResultTag.fail);
    }

    /// <summary>
    /// 添加流程实例
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public TData onAddFlowinstance(Fw_FlowinstanceRequest param)
    {
        var flowscheme = _flowschemeRepository.GetFirstOrDefault(u => u.Id == param.SchemeId);
        if (flowscheme == null)
        {
            throw new Exception("流程模板不存在");
        }
        var instance = param.MapTo<Fw_FlowinstanceRequest,Fw_Flowinstance>();
        instance.Id = SnowflakeId.Id;
        instance.SchemeContent = flowscheme.SchemeContent;
        instance.FrmContentData = flowscheme.FrmContentData;
        instance.ConfluenceNo = 0;
        instance.ConfluenceOk = 0;

        FlowRuntime flowRuntime = new FlowRuntime(instance);
        instance.ActivityId = flowRuntime.currentNodeId;
        instance.ActivityName = flowRuntime.nodeName;
        instance.ActivityType = (int)flowRuntime.currentNodeType;
        instance.PreviousId = flowRuntime.previousId;
        instance.MakerList = _flowHandle.GetFlowNextMakers(flowRuntime);

        instance.CreateTime = DateTime.Now;
        instance.CreateBy = "system";
        var count = _flowinstanceRepository.Insert(instance);

        return count > 0 ? new TData(ResultTag.success) : new TData(ResultTag.fail);
    }

    /// <summary>
    /// 更新流程实例
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public TData onUpdateFlowinstance(Fw_FlowinstanceRequest param)
    {
        var model = _flowschemeRepository.GetByKey(param.SchemeId);
        if (model == null)
        {
            throw new Exception("流程模板不存在");
        }
        var entity = _flowinstanceRepository.GetByKey(param.Id);
        if (entity.CustomName == param.CustomName)
        {
            throw new Exception("流程名称已经存在");
        }
        entity.SchemeContent = model.SchemeContent;
        entity.UpdateTime = DateTime.Now;
        entity.UpdateBy = "system";
        var count = _flowinstanceRepository.Update(entity);
        return count > 0 ? new TData(ResultTag.success) : new TData(ResultTag.fail);
    }

    /// <summary>
    /// 审核
    /// </summary>
    public void onProcessApproval(ApprovalReqest request, Action successHandler = null, Action finallyAction = null)
    {
        bool isReject = TagState.Reject.Equals(request.ApprovalReslut);
        if (isReject) //驳回
        {
            onProcessApprovalReject(request);
        }
        else
        {
            onProcessApprovalResolve(request, successHandler, finallyAction);
        }
    }

    #region 私有方法

    /// <summary>
    /// 审核通过
    /// </summary>
    /// <param name="instanceId"></param>
    /// <returns></returns>
    private void onProcessApprovalResolve(ApprovalReqest request, Action successHandler = null, Action finallyAction = null)
    {
        var instanceId = request.FlowInstanceId;

        Fw_Flowinstance flowInstance = _flowinstanceRepository.GetByKey(instanceId);

        if (user.UserId != WebConstant.SuperAdmin && !flowInstance.MakerList.Contains(user.UserId))
        {
            throw new Exception("当前用户没有审批该节点权限");
        }
        var optTag = new OptionResultTag
        {
            UserName = user.UserName,
            UserId = user.UserId,
            Taged = request.ApprovalReslut,
            TagedTime = DateTime.Now
        };
        FlowRuntime wfruntime = new FlowRuntime(flowInstance);

        _flowinstanceRepository.UnitOfWork.BeginTransaction();

        #region 会签

        if (wfruntime.counterSign) //当前节点是会签节点
        {
            int confluenceRes = _flowHandle.onGetNodeConfluenceType(wfruntime, optTag);

            if (confluenceRes == FlowNodeStatus.Join) //会签结束
            {
                if (optTag.Taged == TagState.No)
                {
                    flowInstance.IsFinish = FlowInstanceStatus.Disagree;
                    //返回给申请人
                    _flowHandle.onRunToApplyUser(flowInstance, wfruntime);

                    optTag.Description = $"【审核不同意】流程结束,【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】" + ",备注：" + request.ApprovalRemark;
                }
                else
                {
                    //流转到下一步
                    _flowHandle.onRunToNextApprovalNode(flowInstance, wfruntime);

                    flowInstance.ConfluenceOk = 0;
                    flowInstance.ConfluenceNo = 0;
                    flowInstance.IsFinish = wfruntime.nextNodeId != Define.FlowEndCode ? FlowInstanceStatus.Running : FlowInstanceStatus.Finished;

                    optTag.Description = $"【会签审核通过】流程继续进行,【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】" + ",备注：" + request.ApprovalRemark;
                }
                _flowHandle.AddTransHistory(wfruntime);
            }
            else //会签开始
            {
                flowInstance.ConfluenceOk = wfruntime.confluenceOk;
                flowInstance.ConfluenceNo = wfruntime.confluenceNo;
                optTag.Description = $"【会签审核开始】流程继续进行,【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】" + ",备注：" + request.ApprovalRemark;
            }
        }

        #endregion 会签

        #region 一般审核

        else
        {
            if (optTag.Taged == TagState.Ok)
            {
                flowInstance.IsFinish = wfruntime.nextNodeId != Define.FlowEndCode ? FlowInstanceStatus.Running : FlowInstanceStatus.Finished;
                //流转到下一步
                _flowHandle.onRunToNextApprovalNode(flowInstance, wfruntime);
                string flowStatus = flowInstance.IsFinish == FlowInstanceStatus.Running ? "流程继续进行" : "流程结束";

                optTag.Description = $"【审核通过】{flowStatus},【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】" + ",备注：" + request.ApprovalRemark;
            }
            else if (optTag.Taged == TagState.No)
            {
                flowInstance.IsFinish = FlowInstanceStatus.Disagree; //表示该节点不同意
                //返回给申请人
                _flowHandle.onRunToApplyUser(flowInstance, wfruntime);

                optTag.Description = $"【审核不同意】流程结束,【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】" + ",备注：" + request.ApprovalRemark;
            }
            _flowHandle.AddTransHistory(wfruntime);
        }

        #endregion 一般审核

        //flowInstance.FrmData = wfruntime.FrmData;
        flowInstance.UpdateBy = user.UserName;
        flowInstance.UpdateTime = DateTime.Now;

        _flowinstanceRepository.Update(flowInstance);
        _flowHandle.AddOperationHistory(wfruntime, optTag);
        _flowHandle.AddApprovalRecordHistory(wfruntime, optTag, optTag => { optTag.Description = request.ApprovalRemark; });
        _flowinstanceRepository.UnitOfWork.Commit();
        ////给流程创建人发送通知信息
        //    _messageApp.SendMsgTo(flowInstance.CreateUserId,
        //        $"你的流程[{flowInstance.CustomName}]已被{user.Name}处理。处理情况如下:{flowInstanceOperationHistory.Content}");
        //wfruntime.NotifyThirdParty(_httpClientFactory.CreateClient(), tag);

        if (flowInstance.IsFinish == FlowInstanceStatus.Finished)
        {
            successHandler?.Invoke();
            finallyAction?.Invoke();
            //处理流程完成后的业务流程
        }
        if (flowInstance.IsFinish == FlowInstanceStatus.Rejected || flowInstance.IsFinish == FlowInstanceStatus.Disagree)
        {
            //处理流程完成后的业务流程
        }
    }

    /// <summary>
    /// 审核驳回
    /// 返回到上一步审批人
    /// </summary>
    /// <returns></returns>
    private void onProcessApprovalReject(ApprovalReqest reqest)
    {
        Fw_Flowinstance flowInstance = _flowinstanceRepository.GetByKey(reqest.FlowInstanceId);
        if (user.UserId != WebConstant.SuperAdmin && !flowInstance.MakerList.Contains(user.UserId))
        {
            throw new Exception("当前用户没有驳回该节点权限");
        }
        FlowRuntime wfruntime = new FlowRuntime(flowInstance);

        wfruntime.nextNodeId = flowInstance.PreviousId;
        wfruntime.nextNode = wfruntime.Nodes[flowInstance.PreviousId];

        flowInstance.ActivityId = flowInstance.PreviousId;
        flowInstance.ActivityType = (int)wfruntime.GetNodeType(flowInstance.PreviousId);
        flowInstance.ActivityName = wfruntime.Nodes[flowInstance.PreviousId].nodeName;
        flowInstance.MakerList = _flowHandle.GetNodeCurrentMarkers(wfruntime.Nodes[flowInstance.PreviousId], flowInstance.ApplyUserId);

        flowInstance.PreviousId = wfruntime.currentNodeId;
        OptionResultTag optionTag = new()
        {
            UserName = user.UserName,
            UserId = user.UserId,
            Taged = reqest.ApprovalReslut,
            TagedTime = DateTime.Now,
            Description = $"【审核驳回】流程返回到上一步审批人，【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】" + ",备注：" + reqest.ApprovalRemark,
        };

        flowInstance.UpdateBy = user.UserName;
        flowInstance.UpdateTime = DateTime.Now;

        _flowinstanceRepository.UnitOfWork.BeginTransaction();
        _flowinstanceRepository.Update(flowInstance);
        _flowHandle.AddTransHistory(wfruntime); //工作流程流转记录
        _flowHandle.AddOperationHistory(wfruntime, optionTag);   //操作记录
        _flowinstanceRepository.UnitOfWork.Commit();

        //给流程创建人发送通知信息
        //SendMsgTo(flowInstance.CreateUserId, $"你的流程[{flowInstance.CustomName}]已被{user.Name}驳回。备注信息:{reqest.VerificationOpinion}");
    }

    #endregion 私有方法

    /// <summary>启动流程</summary>
    /// <remarks> 通常是对状态为【草稿】的流程进行操作，进入运行状态 </remarks>
    public void onProcessInstanceStart(string flowInstanceId)
    {
        Fw_Flowinstance flowInstance = _flowinstanceRepository.GetByKey(flowInstanceId);
        var wfruntime = new FlowRuntime(flowInstance);
        OptionResultTag optionTag = new()
        {
            UserName = user.UserName,
            UserId = user.UserId,
            Taged = TagState.Ok,
            TagedTime = DateTime.Now,
            Description = $"【流程启动】流程进行，由用户{user.UserName}启动，【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】",
        };
        flowInstance.ActivityId = wfruntime.nextNodeId;
        flowInstance.ActivityType = wfruntime.nextNode?.nodeType ?? (int)FlowNodeType.End;
        flowInstance.ActivityName = wfruntime.nextNode?.nodeName ?? Define.FlowEndTitle;
        flowInstance.PreviousId = wfruntime.currentNodeId;

        flowInstance.MakerList = _flowHandle.GetFlowNextMakers(wfruntime, wfruntime.nextNodeId);
        flowInstance.IsFinish = wfruntime.nextNodeId != Define.FlowEndCode ? FlowInstanceStatus.Running : FlowInstanceStatus.Finished;

        _flowinstanceRepository.UnitOfWork.BeginTransaction();

        _flowinstanceRepository.Update(flowInstance);

        _flowHandle.AddTransHistory(wfruntime);

        _flowHandle.AddOperationHistory(wfruntime, optionTag);

        _flowinstanceRepository.UnitOfWork.Commit();
    }

    /// <summary>
    /// 召回流程
    /// </summary>
    /// <param name="flowInstanceId">流程实例id</param>
    public void onProcessInstanceReCall(string flowInstanceId)
    {
        Fw_Flowinstance flowInstance = _flowinstanceRepository.GetByKey(flowInstanceId);
        FlowRuntime wfruntime = new FlowRuntime(flowInstance);
        OptionResultTag optionTag = new()
        {
            UserName = user.UserName,
            UserId = user.UserId,
            Taged = TagState.No,
            TagedTime = DateTime.Now,
            Description = $"【流程召回】流程返回到开始节点，【{wfruntime.nodeName}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}】",
        };
        string startNodeId = wfruntime.startNodeId; //起始节点

        flowInstance.IsFinish = FlowInstanceStatus.Draft;
        flowInstance.PreviousId = flowInstance.ActivityId;
        flowInstance.ActivityId = startNodeId;
        flowInstance.ActivityType = (int)wfruntime.GetNodeType(startNodeId);
        flowInstance.ActivityName = wfruntime.Nodes[startNodeId].nodeName;
        flowInstance.MakerList = flowInstance.ApplyUserId;

        _flowinstanceRepository.UnitOfWork.BeginTransaction();
        _flowinstanceRepository.Update(flowInstance);
        _flowHandle.AddTransHistory(wfruntime);
        _flowHandle.AddOperationHistory(wfruntime, optionTag);
        _flowinstanceRepository.UnitOfWork.Commit();
    }

    #region 流程实例预览

    /// <summary>
    /// 获取审批节点链路用于预览显示
    /// </summary>
    /// <remarks>审批流程实例审批人预览</remarks>
    /// <param name="Id">实例ID</param>
    /// <returns></returns>
    public async Task<List<FlowNode>> GetApprovalNodeList(string Id)
    {
        var instance = await _flowinstanceRepository.GetByKeyAsync(Id);

        FlowRuntime runtime = new FlowRuntime(instance);
        TData<object> tData = new TData<object>();

        var list = new List<FlowNode>();
        var startNodeId = runtime.startNodeId;
        FlowNode currentNode = runtime.GetFlowNodeById(runtime.startNodeId);
        currentNode.nodeDisplayName = runtime.applyUserName;
        list.Add(currentNode);

        while (!string.IsNullOrWhiteSpace(startNodeId))
        {
            var node = runtime.GetNextApprovalNode(startNodeId);
            if (node == null) { break; }
            node.nodeFrom = startNodeId;
            node.prevId = new List<string>() { startNodeId };
            startNodeId = node.nodeId;
            if (!list.Any(c => c.nodeId == node.nodeId))
            {
                list.Add(node);
            }
        }
        return GetApprovalNodeRebuild(list);
    }

    private List<FlowNode> GetApprovalNodeRebuild(List<FlowNode> nodes)
    {
        foreach (var item in nodes)
        {
            if (string.IsNullOrWhiteSpace(item.nodeFrom)) { continue; }
            var node = nodes.First(c => c.nodeId == item.nodeFrom);
            node.nodeTo = new List<string>() { item.nodeId };
        }
        return nodes;
    }

    #endregion 流程实例预览
}